package com.ymt.fmd.platform.service;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.logging.Logger;

import com.ymt.fmd.appboot.prop.FmdProperties;
import com.ymt.fmd.appboot.prop.OssFormProperties;
import org.apache.http.entity.ContentType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.stereotype.Service;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.aliyun.oss.model.ObjectMetadata;
import com.ymt.fmd.platform.dao.mysql.PFormMapper;
import com.ymt.fmd.platform.dao.mysql.PFormVersionMapper;
import com.ymt.fmd.platform.formdesigner.parser.Parser;
import com.ymt.fmd.platform.formdesigner.parser.ParserManager;
import com.ymt.fmd.platform.formdesigner.parser.impl.Json2htmlParser;
import com.ymt.fmd.platform.model.FormPurpose;
import com.ymt.fmd.platform.model.PForm;
import com.ymt.fmd.platform.model.PFormVersion;
import com.ymt.fmd.platform.model.PFormVersionKey;
import com.ymt.fmd.util.AES;
import com.ymt.fmd.util.Const;
import com.ymt.fmd.util.HtmlUtil;


/**
 * 
 * @author Johnny
 *
 */
@Service
@EnableConfigurationProperties(value = {FmdProperties.class, OssFormProperties.class})
public class FormDesignerService {
	
	private Logger logger = Logger.getLogger(FormDesignerService.class.getName());

	@Autowired
	private FmdProperties fmdProperties;

	@Autowired
	private OssFormProperties ossFormProperties;
	
	@Autowired
	private PFormMapper fDao;
	
	@Autowired
	private PFormVersionMapper fvDao;

	@Autowired
	private ParserManager parserManager;

	@Autowired
	private OssFormService ossFormService;
	

	/**
	 * deploy form file to server
	 * @param serverUrl
	 * @param formid
	 * @param versionid
	 * @param skin
	 * @param realPath
	 * @return
	 */
	public String deployVersion(String serverUrl, String formid, String versionid, String skin, String realPath) {
		PForm form = fDao.selectByPrimaryKey(formid);
		PFormVersionKey key = new PFormVersionKey();
		key.setFormid(formid);
		key.setVersionid(versionid);
		PFormVersion version = fvDao.selectByPrimaryKey(key);
		return deployVersion(serverUrl, form, version, skin, realPath);
		/*String errMsg="";
		String tenantPath = form.getTenantId()!=null && form.getTenantId()>0 ? (form.getTenantId()+"/") : "0/";
		int tenantIdForPush = form.getTenantId()!=null ? form.getTenantId() : 0;
		try {
			String[] skins = skin==null ? Settings.getValue("fmd.supported.skins").split(",") : skin.split(",");
			String[] urls = serverUrl.split("\\|");
			for (String sk : skins) {
				for (String lang : Const.LANGS) {
					//form file
					String formFileName = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, null);
					String previewFolder = HtmlUtil.getPreviewRelativePath(sk);
					String fullPath = realPath + "/" + previewFolder + "/generated/" + tenantPath+formFileName;
					//if (!new File(fullPath).exists()) {
						String g1 = generatePreview(form, version, lang, sk, Json2htmlParser.PARSER_JS_PARSER, null, realPath);
						if (!JSONObject.parseObject(g1).getBoolean("success")) {
							return "{\"success\":false, \"err\":\"Local error: preview file generation failed.\"}";
						}
					//}
					for (String url : urls) {
						String s = deployVersionFile(url, fullPath, formFileName, String.valueOf(tenantIdForPush));
						if (!JSONObject.parseObject(s).getBoolean("success")) {
							errMsg += "\n"+s;
						}
					}
					
					//form file for printing
					if (fmdPrintEnabled) {
						formFileName = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, Json2htmlParser.PARSER_JS_PRINTER);
						fullPath = realPath + "/" + previewFolder + "/generated/"+tenantPath+formFileName;
						//if (!new File(fullPath).exists()) {
							String g2 = generatePreview(form, version, lang, sk, Json2htmlParser.PARSER_JS_PRINTER, Json2htmlParser.PARSER_JS_PRINTER, realPath);
							if (!JSONObject.parseObject(g2).getBoolean("success")) {
								return "{\"success\":false, \"err\":\"Local error: print preview file generation failed.\"}";
							}
						//}
						for (String url : urls) {
							String s = deployVersionFile(url, fullPath, formFileName, String.valueOf(tenantIdForPush));
							if (!JSONObject.parseObject(s).getBoolean("success")) {
								errMsg += "\n"+s;
							}
						}
					}
				}
			}
			if (errMsg.length()==0) {
				return "{\"success\":true}";
			}
		} catch (Exception e) {
			e.printStackTrace();
			errMsg = e.getMessage();
		}
		return "{\"success\":false, \"err\":\"Local error: "+errMsg+"\"}";*/
	}
	
	public String deployAll(String serverUrl, String skin, String realPath) {
		Map<String, Object> paramsArgs = new HashMap<String, Object>();
		Map<String, Object> params = new HashMap<String, Object>();
		params.put("args", paramsArgs);
		int total = Integer.parseInt(fvDao.pagingSelectCount(params).get("COUNT").toString());
		Map<String, Object> paramsV = new HashMap<String, Object>();
		paramsV.put("args", paramsArgs);
		paramsV.put("orderby", " order by FORMID,VERSIONID DESC ");
		for (int i=0; i<total; i++) {
			paramsV.put("fromRow", i);
			paramsV.put("rows", 1);
			List<Map<String, ?>> list = fvDao.pagingSelect(paramsV);
			if (list!=null && list.get(0)!=null) {
				String formid = (String)list.get(0).get("FORMID");
				String versionid = (String)list.get(0).get("VERSIONID");
				String rtnString = deployVersion(serverUrl, formid, versionid, skin, realPath);
				if (rtnString.indexOf("true")<=0) {
					return rtnString;
				}
			}
		}
		return "{\"success\":true}";
	}

	/**
	 * generate preview file
	 * @param formid
	 * @param versionid
	 * @param lang
	 * @param skin
	 * @param realPath
	 * @return
	 */
	public String generatePreview(String formid, 
			String versionid, 
			String lang,
			String skin, 
			String parserJsName,
			String fileSuffix,
			String realPath) {
		PForm form = fDao.selectByPrimaryKey(formid);
		PFormVersionKey key = new PFormVersionKey();
		key.setFormid(formid);
		key.setVersionid(versionid);
		PFormVersion version = fvDao.selectByPrimaryKey(key);
		return generatePreview(form,
				version, 
				lang,
				skin, 
				parserJsName,
				fileSuffix,
				realPath);
	}

	/**
	 * deploy form file to server
	 * @param serverUrl
	 * @param form
	 * @param version
	 * @param skin
	 * @param realPath
	 * @return
	 */
	private String deployVersion(String serverUrl, PForm form, PFormVersion version, String skin, String realPath) {
		boolean usingOSS = ossFormProperties.getEndpoint() != null && ossFormProperties.getEndpoint().length()>0;
		boolean fmdPrintEnabled = Boolean.parseBoolean(fmdProperties.getPrintEnabled());

		String formid = version.getFormid();
		String versionid = version.getVersionid();
		String errMsg="";
		String tenantPath = form.getTenantId()!=null && form.getTenantId()>0 ? (form.getTenantId()+"/") : "0/";
		int tenantIdForPush = form.getTenantId()!=null ? form.getTenantId() : 0;
		try {
			String[] skins = skin==null ? fmdProperties.getSupportedSkins().split(",") : skin.split(",");
			for (String sk : skins) {
				for (String lang : Const.LANGS) {
					if (usingOSS) {	//form file on OSS
						String ossPathPrefix = "forms/"+ AES.encrypt(String.valueOf(tenantIdForPush)) + "/" + form.getFormtype().toLowerCase()+"/";
						String fileName = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, null, "html");
						StringBuilder htmlStr = generateFormStr(form, version, lang, sk, Json2htmlParser.PARSER_JS_PARSER, realPath);
						uploadCdnFormByPurpose(ossPathPrefix, fileName, htmlStr);
						if (fmdPrintEnabled) {
							String fileName1 = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, null, "html");
							StringBuilder htmlStr1 = generateFormStr(form, version, lang, sk, Json2htmlParser.PARSER_JS_PRINTER, realPath);
							uploadCdnFormByPurpose(ossPathPrefix, fileName1, htmlStr1);
						}
					} else {	//form file on server realpath
						
						//form file
						String formFileName = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, null, "jsp");
						String previewFolder = HtmlUtil.getPreviewRelativePath(sk, fmdProperties.getPreviewFolder());
						String fullPath = realPath + "/" + previewFolder + "/generated/" + tenantPath+formFileName;
						logger.finer("formFile path=" + fullPath);
						//if (!new File(fullPath).exists()) {
							String g1 = generatePreview(form, version, lang, sk, Json2htmlParser.PARSER_JS_PARSER, null, realPath);
							if (!JSONObject.parseObject(g1).getBoolean("success")) {
								return "{\"success\":false, \"err\":\"Local error: preview file generation failed.\"}";
							}
						//}

						String[] urls = null;
						if (serverUrl==null || serverUrl.length()==0) {
							errMsg += "NO_SERVER_SPECIFIED";
						}
						urls = serverUrl.split("\\|");
						if (urls==null || urls.length==0) {
							errMsg += "NO_SERVER_SPECIFIED";
						} else {
							for (String url : urls) {
								String s = deployVersionFile(url, fullPath, formFileName, String.valueOf(tenantIdForPush));
								if (!JSONObject.parseObject(s).getBoolean("success")) {
									errMsg += "\n"+s;
								}
							}

							//form file for printing
							if (fmdPrintEnabled) {
								formFileName = HtmlUtil.getPreviewFileName(formid, versionid, lang, sk, Json2htmlParser.PARSER_JS_PRINTER, "jsp");
								fullPath = realPath + "/" + previewFolder + "/generated/"+tenantPath+formFileName;
								logger.finer("formFile for printing path=" + fullPath);
								//if (!new File(fullPath).exists()) {
								String g2 = generatePreview(form, version, lang, sk, Json2htmlParser.PARSER_JS_PRINTER, Json2htmlParser.PARSER_JS_PRINTER, realPath);
								if (!JSONObject.parseObject(g2).getBoolean("success")) {
									return "{\"success\":false, \"err\":\"Local error: print preview file generation failed.\"}";
								}
								//}
								for (String url : urls) {
									String s = deployVersionFile(url, fullPath, formFileName, String.valueOf(tenantIdForPush));
									if (!JSONObject.parseObject(s).getBoolean("success")) {
										errMsg += "\n"+s;
									}
								}
							}
						}
					}
				}
			}
			if (errMsg.length()==0) {
				return "{\"success\":true}";
			}
		} catch (Exception e) {
			e.printStackTrace();
			errMsg = e.getMessage();
		}
		return "{\"success\":false, \"err\":\"Local error: "+errMsg+"\"}";
	}
	
	/**
	 * upload oss file by purpose
	 * @param ossPathPrefix
	 * @param fileName
	 * @param htmlStr
	 * @throws UnsupportedEncodingException
	 * @throws Exception
	 */
	private void uploadCdnFormByPurpose(String ossPathPrefix, String fileName, StringBuilder htmlStr) throws UnsupportedEncodingException, Exception {
		ObjectMetadata meta = new ObjectMetadata();
		meta.setContentType(ContentType.TEXT_HTML.getMimeType());
		meta.setContentEncoding(Const.ENCODING);
		List<FormPurpose> purposes = getFormPurposes();
		for (FormPurpose purpose : purposes) {
			//TODO check type skin lang
			String buildCdnHtml = buildCdnHtml(purpose, htmlStr);
			String ossPath = ossPathPrefix + purpose.getPurpose() + "/" + fileName;
			logger.finer("uploading OSS file: "+ossPath);
			ossFormService.upload(ossPath, new ByteArrayInputStream(buildCdnHtml.getBytes("UTF-8")), meta);
		}
	}
	
	/**
	 * build the html string by purpose
	 * @param purpose
	 * @param htmlStr
	 * @return
	 */
	private String buildCdnHtml(FormPurpose purpose, StringBuilder htmlStr) {
		return purpose.getBeforeString()
				.append(htmlStr)
				.append(purpose.getAfterString())
					.toString();
	}

	/**
	 * generate preview file
	 * @param form
	 * @param version
	 * @param lang
	 * @param skin
	 * @param parserJsName
	 * @param realPath
	 * @return
	 */
	private StringBuilder generateFormStr(PForm form,
			PFormVersion version, 
			String lang,
			String skin, 
			String parserJsName,
			String realPath) {
		
		Parser parser = parserManager.getParser();
		
		try {
			parser.init(fmdProperties, realPath, skin, lang, parserJsName);
			
			if (PForm.TYPE_PROCESS.equalsIgnoreCase(form.getFormtype())) {
				JSONObject formdata = JSONObject.parseObject(version.getFormdata());
				
				//parser modules
				JSONArray blocks = formdata.getJSONObject("formconf").getJSONArray("tabs").getJSONObject(0).getJSONArray("items");
				JSONObject propconfs = formdata.getJSONObject("propconf");
				JSONObject models = formdata.getJSONObject("models");
				
				JSONObject moduleRtn = parser.parseModules(blocks.toString(), propconfs.toString(), models.toString());
				String formmodules = HtmlUtil.formatHtmlCode(moduleRtn.getString("html"));
				String generatedScript = moduleRtn.getString("generatedscript");
				String fmdv = moduleRtn.getString("fmdv");
				
				//put formid versionid to fmdv
				if (fmdv!=null && fmdv.length()>0) {
					JSONObject fmdvobj = JSONObject.parseObject(fmdv);
					fmdvobj.put("formid", version.getFormid());
					fmdvobj.put("versionid", version.getVersionid());
					fmdv = fmdvobj.toString();
				}
				
				logger.finer("generatePreview modules formated=\n"+formmodules);
				
				//parse form
				JSONObject env = new JSONObject();
				env.put("ctxpath", fmdProperties.getTargetappContextpath());
				
				JSONObject arguments = new JSONObject();
				arguments.put("formmodules", formmodules);
				arguments.put("generatedscript", 
						"fmdv="+fmdv+";\n"+
						"fmdv.models="+formdata.getJSONObject("models").toString()+";"+
						"\n\n"+generatedScript);
				arguments.put("refscript", formdata.getString("refscript"));
				addScript(arguments, "readyscript", formdata.getString("readyscript"));
				addScript(arguments, "bodyscript", formdata.getString("bodyscript"));
				addScript(arguments, "datareadyscript", formdata.getString("datareadyscript"));
				
				StringBuilder fHtml = parser.parseForm(PForm.TYPE_PROCESS.toLowerCase(), env.toString(), arguments.toString());
				logger.finer("generatePreview form=\n"+fHtml);
				
				return fHtml;
				
			} else if (PForm.TYPE_DATAEDIT.equalsIgnoreCase(form.getFormtype())) {
				JSONObject formdata = JSONObject.parseObject(version.getFormdata());
				
				//parser modules
				JSONArray rootModules = formdata.getJSONObject("formconf").getJSONArray("tabs").getJSONObject(0).getJSONArray("items");
				JSONObject propconfs = formdata.getJSONObject("propconf");
				JSONObject models = formdata.getJSONObject("models");
				
				JSONObject moduleRtn = parser.parseModules(rootModules.toString(), propconfs.toString(), models.toString());
				String formmodules = HtmlUtil.formatHtmlCode(moduleRtn.getString("html"));
				String generatedScript = moduleRtn.getString("generatedscript");
				String fmdv = moduleRtn.getString("fmdv");
				logger.finer("generatePreview modules formated=\n"+formmodules);
				
				//put formid versionid to fmdv
				if (fmdv!=null && fmdv.length()>0) {
					JSONObject fmdvobj = JSONObject.parseObject(fmdv);
					fmdvobj.put("formid", version.getFormid());
					fmdvobj.put("versionid", version.getVersionid());
					fmdv = fmdvobj.toString();
				}
				
				//parse form
				JSONObject env = new JSONObject();
				env.put("ctxpath", fmdProperties.getTargetappContextpath());
				
				JSONObject arguments = new JSONObject();
				arguments.put("formmodules", formmodules);
				arguments.put("generatedscript", 
						"fmdv="+fmdv+";\n"+
						"fmdv.models="+formdata.getJSONObject("models").toString()+";"+
						"\n\n"+generatedScript);
				arguments.put("refscript", formdata.getString("refscript"));
				addScript(arguments, "readyscript", formdata.getString("readyscript"));
				addScript(arguments, "bodyscript", formdata.getString("bodyscript"));
				addScript(arguments, "datareadyscript", formdata.getString("datareadyscript"));
				
				StringBuilder fHtml = parser.parseForm(PForm.TYPE_DATAEDIT.toLowerCase(), env.toString(), arguments.toString());
				logger.finer("generatePreview form=\n"+fHtml);
				
				return fHtml;
			}
			logger.warning("Form type:"+form.getFormtype()+" is not supported!");
			return null;
		} catch (Exception e) {
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * generate preview file
	 * @param form
	 * @param version
	 * @param lang
	 * @param skin
	 * @param realPath
	 * @return
	 */
	/*private String generatePreview(PForm form,
			PFormVersion version, 
			String lang,
			String skin, 
			String parserJsName,
			String fileSuffix,
			String realPath) {
		
		Parser parser = ParserManager.getParser();
		
		try {
			parser.init(realPath, skin, lang, parserJsName);
			
			String tenantPath = form.getTenantId()!=null && form.getTenantId()>0 ? (form.getTenantId()+"/") : "0/";
			String previewFolder = HtmlUtil.getPreviewRelativePath(skin);
			String previewFolderPath = realPath + "/" + previewFolder + "/generated/" + tenantPath;
			String formfile = "/" + previewFolder + "/generated/" + tenantPath + HtmlUtil.getPreviewFileName(version.getFormid(), version.getVersionid(), lang, skin, fileSuffix);
			String relativePath = formfile;
			
			if (PForm.TYPE_PROCESS.equalsIgnoreCase(form.getFormtype())) {
				JSONObject formdata = JSONObject.parseObject(version.getFormdata());
				
				//parser modules
				JSONArray blocks = formdata.getJSONObject("formconf").getJSONArray("tabs").getJSONObject(0).getJSONArray("items");
				JSONObject propconfs = formdata.getJSONObject("propconf");
				JSONObject models = formdata.getJSONObject("models");
				
				JSONObject moduleRtn = parser.parseModules(blocks.toString(), propconfs.toString(), models.toString());
				String formmodules = HtmlUtil.formatHtmlCode(moduleRtn.getString("html"));
				String generatedScript = moduleRtn.getString("generatedscript");
				String fmdv = moduleRtn.getString("fmdv");
				
				//put formid versionid to fmdv
				if (fmdv!=null && fmdv.length()>0) {
					JSONObject fmdvobj = JSONObject.parseObject(fmdv);
					fmdvobj.put("formid", version.getFormid());
					fmdvobj.put("versionid", version.getVersionid());
					fmdv = fmdvobj.toString();
				}
				
				logger.finer("generatePreview modules formated=\n"+formmodules);
				
				//parse form
				JSONObject env = new JSONObject();
				env.put("ctxpath", Settings.getValue(Settings.FMD_FORMVARS, "targetapp.contextpath"));
				
				JSONObject arguments = new JSONObject();
				arguments.put("formmodules", formmodules);
				arguments.put("generatedscript", 
						"fmdv="+fmdv+";\n"+
						"fmdv.models="+formdata.getJSONObject("models").toString()+";"+
						"\n\n"+generatedScript);
				arguments.put("refscript", formdata.getString("refscript"));
				addScript(arguments, "readyscript", formdata.getString("readyscript"));
				addScript(arguments, "bodyscript", formdata.getString("bodyscript"));
				addScript(arguments, "datareadyscript", formdata.getString("datareadyscript"));
				
				StringBuilder fHtml = parser.parseForm(PForm.TYPE_PROCESS.toLowerCase(), env.toString(), arguments.toString());
				logger.finer("generatePreview form=\n"+fHtml);
				
				//generate file
				//get js parser config for form type
				JSONObject fpcfg = parser.getFormJsParserConfig(PForm.TYPE_PROCESS.toLowerCase());
				logger.finer("generatePreview form js parser config="+fpcfg);
				if (fpcfg!=null) {
					String wrapperPage = fpcfg.getString("wrapper_page");
					if (wrapperPage!=null && wrapperPage.trim().length()>0) {
						relativePath = "/" + previewFolder
								+ "/"
								+ wrapperPage
								+ "?formfile="
								+ formfile
								+ "&lang="+lang;//wrapper need a lang parameter
					}
				}
				File pFolder = new File(previewFolderPath);
				if (!pFolder.exists()) {
					pFolder.mkdirs();
				}
				HtmlUtil.generatedPreviewFile(realPath + formfile, fHtml.toString());
				
				return "{\"success\":true, \"relativePath\":\""+relativePath+"\"}";
			} else if (PForm.TYPE_DATAEDIT.equalsIgnoreCase(form.getFormtype())) {
				JSONObject formdata = JSONObject.parseObject(version.getFormdata());
				
				//parser modules
				JSONArray rootModules = formdata.getJSONObject("formconf").getJSONArray("tabs").getJSONObject(0).getJSONArray("items");
				JSONObject propconfs = formdata.getJSONObject("propconf");
				JSONObject models = formdata.getJSONObject("models");
				
				JSONObject moduleRtn = parser.parseModules(rootModules.toString(), propconfs.toString(), models.toString());
				String formmodules = HtmlUtil.formatHtmlCode(moduleRtn.getString("html"));
				String generatedScript = moduleRtn.getString("generatedscript");
				String fmdv = moduleRtn.getString("fmdv");
				logger.finer("generatePreview modules formated=\n"+formmodules);
				
				//put formid versionid to fmdv
				if (fmdv!=null && fmdv.length()>0) {
					JSONObject fmdvobj = JSONObject.parseObject(fmdv);
					fmdvobj.put("formid", version.getFormid());
					fmdvobj.put("versionid", version.getVersionid());
					fmdv = fmdvobj.toString();
				}
				
				//parse form
				JSONObject env = new JSONObject();
				env.put("ctxpath", Settings.getValue(Settings.FMD_FORMVARS, "targetapp.contextpath"));
				
				JSONObject arguments = new JSONObject();
				arguments.put("formmodules", formmodules);
				arguments.put("generatedscript", 
						"fmdv="+fmdv+";\n"+
						"fmdv.models="+formdata.getJSONObject("models").toString()+";"+
						"\n\n"+generatedScript);
				arguments.put("refscript", formdata.getString("refscript"));
				addScript(arguments, "readyscript", formdata.getString("readyscript"));
				addScript(arguments, "bodyscript", formdata.getString("bodyscript"));
				addScript(arguments, "datareadyscript", formdata.getString("datareadyscript"));
				
				StringBuilder fHtml = parser.parseForm(PForm.TYPE_DATAEDIT.toLowerCase(), env.toString(), arguments.toString());
				logger.finer("generatePreview form=\n"+fHtml);
				
				//generate file
				//get js parser config for form type
				JSONObject fpcfg = parser.getFormJsParserConfig(PForm.TYPE_DATAEDIT.toLowerCase());
				logger.finer("generatePreview form js parser config="+fpcfg);
				if (fpcfg!=null) {
					String wrapperPage = fpcfg.getString("wrapper_page");
					if (wrapperPage!=null && wrapperPage.trim().length()>0) {
						relativePath = "/" + previewFolder
								+ "/"
								+ wrapperPage
								+ "?formfile="
								+ formfile
								+ "&lang="+lang;//wrapper need a lang parameter
					}
				}
				File pFolder = new File(previewFolderPath);
				if (!pFolder.exists()) {
					pFolder.mkdirs();
				}
				HtmlUtil.generatedPreviewFile(realPath + formfile, fHtml.toString());
				
				return "{\"success\":true, \"relativePath\":\""+relativePath+"\"}";
			}
			return "{\"success\":false, \"err\":\"Form type:"+form.getFormtype()+" is not supported!\"}";
		} catch (Exception e) {
			e.printStackTrace();
			return "{\"success\":false, \"err\":\""+e.getMessage()+"\"}";
		}
	}*/
	private String generatePreview(PForm form,
			PFormVersion version, 
			String lang,
			String skin, 
			String parserJsName,
			String fileSuffix,
			String realPath) {
		
		Parser parser = parserManager.getParser();
		
		try {
			parser.init(fmdProperties, realPath, skin, lang, parserJsName);
			
			String tenantPath = form.getTenantId()!=null && form.getTenantId()>0 ? (form.getTenantId()+"/") : "0/";
			String previewFolder = HtmlUtil.getPreviewRelativePath(skin, fmdProperties.getPreviewFolder());
			String previewFolderPath = realPath + "/" + previewFolder + "/generated/" + tenantPath;
			String formfile = "/" + previewFolder + "/generated/" + tenantPath + HtmlUtil.getPreviewFileName(version.getFormid(), version.getVersionid(), lang, skin, fileSuffix, "jsp");
			String relativePath = formfile;
			
			//add jsp declaration
			StringBuilder fHtml = generateFormStr(form, version, lang, skin, parserJsName, realPath);
			fHtml.insert(0, "<%@ page language=\"java\" contentType=\"text/html; charset=UTF-8\" pageEncoding=\"UTF-8\"%>\n");
			
			if (PForm.TYPE_PROCESS.equalsIgnoreCase(form.getFormtype())) {
				
				//generate file
				//get js parser config for form type
				JSONObject fpcfg = parser.getFormJsParserConfig(PForm.TYPE_PROCESS.toLowerCase());
				logger.finer("generatePreview form js parser config="+fpcfg);
				if (fpcfg!=null) {
					String wrapperPage = fpcfg.getString("wrapper_page");
					if (wrapperPage!=null && wrapperPage.trim().length()>0) {
						relativePath = "/" + previewFolder
								+ "/"
								+ wrapperPage
								+ "?formfile="
								+ formfile
								+ "&lang="+lang;//wrapper need a lang parameter
					}
				}
				File pFolder = new File(previewFolderPath);
				if (!pFolder.exists()) {
					pFolder.mkdirs();
				}
				HtmlUtil.generatedPreviewFile(realPath + formfile, fHtml.toString());
				
				return "{\"success\":true, \"relativePath\":\""+relativePath+"\"}";
			} else if (PForm.TYPE_DATAEDIT.equalsIgnoreCase(form.getFormtype())) {
				
				//generate file
				//get js parser config for form type
				JSONObject fpcfg = parser.getFormJsParserConfig(PForm.TYPE_DATAEDIT.toLowerCase());
				logger.finer("generatePreview form js parser config="+fpcfg);
				if (fpcfg!=null) {
					String wrapperPage = fpcfg.getString("wrapper_page");
					if (wrapperPage!=null && wrapperPage.trim().length()>0) {
						relativePath = "/" + previewFolder
								+ "/"
								+ wrapperPage
								+ "?formfile="
								+ formfile
								+ "&lang="+lang;//wrapper need a lang parameter
					}
				}
				File pFolder = new File(previewFolderPath);
				if (!pFolder.exists()) {
					pFolder.mkdirs();
				}
				HtmlUtil.generatedPreviewFile(realPath + formfile, fHtml.toString());
				
				return "{\"success\":true, \"relativePath\":\""+relativePath+"\"}";
			}
			return "{\"success\":false, \"err\":\"Form type:"+form.getFormtype()+" is not supported!\"}";
		} catch (Exception e) {
			e.printStackTrace();
			return "{\"success\":false, \"err\":\""+e.getMessage()+"\"}";
		}
	}
	
	/**
	 * deploy file to server
	 * @param serverUrl
	 * @param formFileName
	 * @return
	 * @throws Exception
	 */
	private String deployVersionFile(String serverUrl, String fullPath, String formFileName, String tenantId) throws Exception {
		// 创建一个新的URL实例url
		URL url = new URL(serverUrl);
		// 根据url建立连接
		URLConnection con = url.openConnection();
		
		con.setRequestProperty("formfilename", formFileName);
		con.setRequestProperty(Const.TENANT_ID, tenantId);

		// 设置该连接可写
		con.setDoOutput(true);
		// 禁用cache
		con.setUseCaches(false);
		// 取出输出流
		OutputStream out = con.getOutputStream();
		// 将该输出流转换为对象输出流
		InputStream in = new FileInputStream(fullPath);
		int c;
		while((c=in.read())!=-1)
		{
			out.write(c);
		}
		in.close();
		out.flush();
		out.close();

		// 取得返回的输入流
		InputStream rin = con.getInputStream();
		ByteArrayOutputStream baos = new ByteArrayOutputStream();  
		int i;  
		while ((i = rin.read()) != -1) {  
		    baos.write(i);  
		}
		String rtn = baos.toString();
		baos.flush();
		baos.close();
		rin.close();
		
		if ("true".equalsIgnoreCase(rtn)) {
			return "{\"success\":true}";
		} else {
			return "{\"success\":false, \"err\":\"Remote error:"+rtn+"\"}";
		}
	}
	
	private void addScript(JSONObject formprop, String name, String script) {
		if (script!=null  && script.length()>0) {
			//script = "<script type=\"text/javascript\">" + script + "</script>";
		} else {
			script = "";
		}
		formprop.put(name, script);
	}
	
	private List<FormPurpose> getFormPurposes() {
		// init by type, skin, lang
		List<FormPurpose> formPurposes = new ArrayList<FormPurpose>(); //must init every time

			/*FormPurpose fp1 = new FormPurpose();
			fp1.setPurpose("tiview");
			fp1.setBeforeString(new StringBuilder(""));
			fp1.setAfterString(new StringBuilder(""));
			formPurposes.add(fp1);

			FormPurpose fp2 = new FormPurpose();
			fp2.setPurpose("piview");
			fp2.setBeforeString(new StringBuilder(""));
			fp2.setAfterString(new StringBuilder(""));
			formPurposes.add(fp2);*/

		FormPurpose fp1 = new FormPurpose();
		fp1.setPurpose("inline");
		fp1.setBeforeString(new StringBuilder(""));
		fp1.setAfterString(new StringBuilder(""));
		formPurposes.add(fp1);

		return formPurposes;
	}
	
	/*private void parseItems(Parser parser, JSONObject propconf, JSONObject m) throws Exception {
		JSONArray items = m.optJSONArray("items");
		if (items==null) {
			return;
		}
		for (int i=0; i<items.size(); i++) {
			JSONObject item = items.getJSONObject(i);
			String id = item.getString("id");
			String prop = id==null ? null : propconf.getJSONObject(id).toString();
			logger.finer("generatePreview tab"+parser.parseModule(item.toString(), prop));
			parseItems(parser, propconf, item);
		}
	}*/
	
}